<?php
/**
 * Created by PhpStorm
 * User: shen.zk
 * Date: 2023/10/26
 * Time: 15:26
 * Comment: ''
 */

namespace App\Service\Common;

use App\Common\Constant;
use App\Common\ResponseCode;
use App\Common\Tools;
use App\Exceptions\BusinessException;
use App\Extensions\Common\RedisService;
use App\Repository\MerchantsCastingLogRepo;
use App\Repository\MerchantsCastingRepo;
use App\Repository\MerchantsInfoRepo;
use App\Service\BaseService;
use App\Params\Common\CastingAccountParam;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Params\Common\MerchantsCastingLogParam;

class MerchantsCastingService extends BaseService
{

    /**
     * 铸造数量更新
     * @param CastingAccountParam $param
     * @return bool
     * @throws BusinessException
     * @author shen.zk
     * @date 2023-10-26 17:25
     */
    public function castingAccountService(CastingAccountParam $param)
    {

        $params = $param->toArray();
        if (!in_array((int)$params['type'],[1,2]))
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL);

        // 访问限制
        $redis = RedisService::getInstance();
        $access_key = Constant::MERCHANTS_CASTING_LIMIT . $params['mid'] . '_' . $params['serial_number'];
        $redis->accessControl($access_key, 3);

        // 商户信息
        $info = MerchantsInfoRepo::getInstance()->getInfoByAccessMid($params['mid']);
        if (empty($info))
            throw new BusinessException(ResponseCode::MERCHANTS_NOT_FUND);

        // 交易流水号是否存在
        $checkSerialNumber = MerchantsCastingLogRepo::getInstance()->getBySerialNumber($params['serial_number']);
        if ($checkSerialNumber)
            throw new BusinessException(ResponseCode::MERCHANTS_CASTING_SERIAL_NUMBER_EXIST);

        // 铸造数量更新
        DB::beginTransaction();
        try {
            $castingInfo = MerchantsCastingRepo::getInstance()->getByMerId($info['mer_id']);
            Log::info("[商户铸造数量]获取商户信息".json_encode($castingInfo,JSON_UNESCAPED_UNICODE));

            // 铸造数量日志
            $log = [
                'mer_id'=>$info['mer_id'],
                'access_id'=>$params['mid'],
                'num'=>$params['number'],
                'serial_number'=>$params['serial_number'],
                'before_change'=>$castingInfo['remaining'],
                'source'=>2,
                'type'=>$params['type'],
                'create_time'=>date('Y-m-d H:i:s'),
                'update_time'=>date('Y-m-d H:i:s'),
            ];
            if ((int)$params['type'] == 2) // 撤销
            {
                if ( !isset($params['revoke_number']) && empty($params['revoke_number']) )
                    throw new BusinessException(ResponseCode::MERCHANTS_CASTING_REVOKE_NUMBER_ERR);

                // 校验原申请流水号是否存在
                $checkRevokeNumber = MerchantsCastingLogRepo::getInstance()->getBySerialNumber($params['revoke_number']);
                Log::info("[铸造撤销]校验原申请流水号是否存在".json_encode($checkRevokeNumber,JSON_UNESCAPED_UNICODE));
                if (empty($checkRevokeNumber))
                    throw new BusinessException(ResponseCode::MERCHANTS_CASTING_SERIAL_NUMBER_NOT_EXIST);

                // 非充值撤销抛出异常
                if ($checkRevokeNumber->source != 2)
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'非法请求']);

                // 已撤销
                if ($checkRevokeNumber->status == 1)
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'非法请求']);

                if ($checkRevokeNumber->type != 1)
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'非法请求']);

                // 校验是否已申请撤销
                $checkRevokeNumberLog = MerchantsCastingLogRepo::getInstance()->getByRevokeNumber($params['revoke_number']);
                Log::info("[铸造撤销]校验是否已申请撤销".json_encode($checkRevokeNumberLog,JSON_UNESCAPED_UNICODE));
                if ($checkRevokeNumberLog)
                    throw new BusinessException(ResponseCode::MERCHANTS_CASTING_REVOKE_NUMBER_EXIST);

                if ($castingInfo['remaining'] - $checkRevokeNumber->num <0)
                {
                    DB::rollBack();
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'铸造数量不足']);
                }

                $result = MerchantsCastingRepo::getInstance()->updateRemaining($info['mer_id'],$checkRevokeNumber['num']);
                if (!$result)
                {
                    DB::rollBack();
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>' 撤销失败']);
                }
                $log['after_change'] = $castingInfo['remaining'] - $checkRevokeNumber->num;


                $save = MerchantsCastingLogRepo::getInstance()->saveLog(['status'=>1,'update_time'=>date('Y-m-d H:i:s')],$checkRevokeNumber->id);
                if (empty($save))
                {
                    DB::rollBack();
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>' 撤销失败']);
                }
                $type = 'reduce';

                $number = $checkRevokeNumber->num;
                $log['num'] = $number;
                $log['revoke_number'] = $params['revoke_number'];
            }

            if ((int)$params['type'] == 1) // 增加
            {

                if (empty($params['number']))
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'铸造数量不能为空']);

                $result = MerchantsCastingRepo::getInstance()->updateIncRemaining($info['mer_id'],$params['number']);

                if (!$result)
                {
                    DB::rollBack();
                    throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'操作失败']);
                }
                $log['after_change'] = $castingInfo['remaining'] + $params['number'];
                $type = 'add';
                $number = $params['number'];
            }

            // 更新创作者创作总数
            $resultTotal = MerchantsCastingRepo::getInstance()->updateTotal($info['mer_id'],$number,$type);

            if (!$resultTotal)
            {
                DB::rollBack();
                throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'操作失败']);
            }
            // 保存流水记录
            $logId = MerchantsCastingLogRepo::getInstance()->saveLog($log);

            if (empty($logId))
            {
                DB::rollBack();
                throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>'操作失败']);
            }

            DB::commit();
        }catch (\Exception $e)
        {
            Log::error("[商户铸造数量]服务异常".$e->getMessage());
            DB::rollBack();
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL,['error'=>$e->getMessage()]);
        }
        return true;
    }

    /**
     * 获取商户变更记录
     * @param MerchantsCastingLogParam $params
     * @return array
     * @author shen.zk
     * @date 2023-10-26 17:44
     */
    public function getMerchantsCastingLogService(MerchantsCastingLogParam $params)
    {
        $data = MerchantsCastingLogRepo::getInstance()->getMerchantsCastingLog($params->toArray());
        return $this->toReturnList($data,$params->getPage(),$params->getPageSize());
    }

    /**
     * 验证流水号是否存在
     * @param string $serial_number
     * @return string
     * @author shen.zk
     * @date 2023-10-27 16:13
     */
    public function checkSerialNumber(string $serial_number)
    {
        $flag = MerchantsCastingLogRepo::getInstance()->getBySerialNumber($serial_number);
        if ($flag)
        {
            $serial_number = Tools::build_hash_no();
            $this->checkSerialNumber($serial_number);
        }

        return $serial_number;
    }
}
